﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using MyWeb.Data;

namespace MyWeb.Datamining.SearchImage
{
    public class clsAlgorithm
    {
        private const int Ncolumn = 3, NSplit = Ncolumn*Nrow;
        private const int Nrow = 3;
        public static List<object[]> compare_result;
        private readonly SqlDataProvider _sqlDataProvider = new SqlDataProvider();
        private DataTable imagelist;

        public int[,] AnalysColor(Bitmap img)
        {
            var colorTable = new int[Ncolumn*Nrow,258];
            int splitColumn = img.Width/Ncolumn,
                splitRow = img.Height/Nrow,
                modColumn = img.Width%Ncolumn,
                modRow = img.Height%Nrow;
            int add_row_pxl = 0;
            int add_clm_pxl = 0;

            for (int b = 1; b <= Nrow; b++)
            {
                add_row_pxl = (b == Nrow) ? modRow : 0;
                for (int a = 1; a <= Ncolumn; a++)
                {
                    add_clm_pxl = (a == Ncolumn) ? modColumn : 0;
                    colorTable[Ncolumn*(b - 1) + (a - 1), 0] = splitColumn + add_clm_pxl;
                    colorTable[Ncolumn*(b - 1) + (a - 1), 1] = splitRow + add_row_pxl;
                    for (int y = (b - 1)*splitRow; y < b*splitRow + add_row_pxl; y++)
                    {
                        for (int x = (a - 1)*splitColumn; x < a*splitColumn + add_clm_pxl; x++)
                        {
                            Color cl = img.GetPixel(x, y);
                            int gScale = ((cl.R + cl.G + cl.B)/3);
                            colorTable[Ncolumn*(b - 1) + (a - 1), gScale + 2] =
                                colorTable[Ncolumn*(b - 1) + (a - 1), gScale + 2] + 1;
                        }
                    }
                }
            }
            return colorTable;
        }

        public void UploadImage(List<string[]> filelist, string idProduct)
        {
            var img = new Bitmap(filelist[0][0]);
            int[,] imageToSave = AnalysColor(img);
            _sqlDataProvider.ExecuteNonQuery(string.Format("EXEC sp_addimage '{0}', '{1}', {2}, {3},{4}", filelist[0][0],
                                                           filelist[0][1],
                                                           img.Width, img.Height, idProduct));

            for (int j = 0; j < imageToSave.GetLength(0); j++)
            {
                var sb =
                    new StringBuilder(string.Format("UPDATE ImageProduct SET GreyColors{0} = GreyColors{0} ", j + 1));
                sb.AppendFormat("+ '{0}*'", imageToSave[j, 0]);
                sb.AppendFormat("+ '{0}*'", imageToSave[j, 1]);
                for (int k = 2; k < imageToSave.GetLength(1); k++)
                {
                    sb.AppendFormat("+ '{0}|'", imageToSave[j, k]);
                }
                sb.AppendFormat(" WHERE FullName = '{0}'", filelist[0][0]);
                _sqlDataProvider.ExecuteNonQuery(sb.ToString());
            }
        }

        public List<object[]> CompareResult(int[,] img_to_search)
        {
            compare_result = new List<object[]>();
            Thread[] comparers = new Thread[8]; //Change zise of array to set number of threads

            for (int i = 0; i < comparers.Length; i++)
            {
                int part = i + 1;
                comparers[i] = new Thread(() => Comparer(imagelist, img_to_search, comparers.Length, part));
            }

            foreach (Thread t in comparers) { t.Start(); }
            foreach (Thread t in comparers) { t.Join(); }

            return QuickSort(compare_result);

            //BubbleSort
            //for (int i = 0; i < compare_result.Count - 1; i++)
            //{
            //    for (int j = i + 1; j < compare_result.Count; j++)
            //    {
            //        if ((decimal)compare_result[i][2] > (decimal)compare_result[j][2])
            //        {
            //            object[] temp = new object[5];
            //            temp = compare_result[i];
            //            compare_result[i] = compare_result[j];
            //            compare_result[j] = temp;
            //        }
            //    }
            //}
        }

        public void Comparer(DataTable imagelist, int[,] img_to_search, float total_part, float part_i)
        {
            decimal offsets = 0, total_pixel1, total_pixel2;
            decimal[,] get_one_image = new decimal[NSplit, 258];
            string grey_colors;
            StringBuilder grey = new StringBuilder(""), size = new StringBuilder("");


            for (int i = (int)((part_i - 1) / total_part * imagelist.Rows.Count); i < (int)(part_i < total_part ? (part_i / total_part * imagelist.Rows.Count) : (imagelist.Rows.Count)); i++)
            {
                object[] img_with_offset = new object[5];
                img_with_offset[0] = imagelist.Rows[i][1];
                img_with_offset[1] = imagelist.Rows[i][2];
                for (int j = 0; j < NSplit; j++)
                {
                    grey_colors = imagelist.Rows[i][5 + j].ToString();
                    grey.Length = 0; size.Length = 0;
                    for (int k = 0, count = 0; k < grey_colors.Length; k++)
                    {
                        if (count < 2)
                        {
                            if (grey_colors[k] != '*') { size.Append(grey_colors[k]); }
                            else
                            {
                                get_one_image[j, count] = Convert.ToDecimal(size.ToString());
                                size.Length = 0;
                                count++;
                            }
                        }
                        else
                        {
                            if (grey_colors[k] != '|') { grey.Append(grey_colors[k]); }
                            else
                            {
                                get_one_image[j, count] = Convert.ToDecimal(grey.ToString());
                                grey.Length = 0;
                                count++;
                            }
                        }
                    }
                }
                offsets = 0;
                for (int j = 0; j < img_to_search.GetLength(0); j++)
                {
                    total_pixel1 = Convert.ToDecimal(img_to_search[j, 0]) * Convert.ToDecimal(img_to_search[j, 1]);
                    total_pixel2 = get_one_image[j, 0] * get_one_image[j, 1];

                    for (int k = 2; k < img_to_search.GetLength(1); k++)
                    {
                        offsets += Math.Abs(get_one_image[j, k] / total_pixel2 - Convert.ToDecimal(img_to_search[j, k]) / total_pixel1);
                        //offsets += Math.Abs(get_one_image[j, k] - Convert.ToDecimal(img_to_search[j, k]));
                    }
                }

                img_with_offset[2] = offsets;
                //img_with_offset[3] = imagelist.Rows[i][3];
                //img_with_offset[4] = imagelist.Rows[i][4];

                compare_result.Add(img_with_offset);
            }
        }

        public List<object[]> QuickSort(List<object[]> calcResult)
        {
            var r = new Random();
            var less = new List<object[]>();
            var greater = new List<object[]>();
            if (calcResult.Count <= 1)
                return calcResult;
            int pos = r.Next(calcResult.Count);

            object[] pivot = calcResult[pos];
            calcResult.RemoveAt(pos);
            foreach (var x in calcResult)
            {
                if ((x != null) && (pivot != null) && (decimal) x[2] <= (decimal) pivot[2])
                {
                    less.Add(x);
                }
                else
                {
                    greater.Add(x);
                }
            }
            return Concat(QuickSort(less), pivot, QuickSort(greater));
        }

        public List<object[]> Concat(List<object[]> less, object[] pivot, List<object[]> greater)
        {
            var sorted = new List<object[]>(less);
            sorted.Add(pivot);

            foreach (var i in greater)
            {
                sorted.Add(i);
            }

            return sorted;
        }
    }
}